package com.unit.manager;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

import javax.inject.Named;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;

import com.unit.handler.DataObjectHandler;
import com.unit.util.ClassUtil;

@Named("assertConvertManager")
public class AssertConvertManager {

	/**
	 * 第一层key为表名+类名，第二层key为columnName，value为fieldName
	 */
	private Map<String, Map<String, String>> cacheForColumnToFieldMap = new ConcurrentHashMap<String, Map<String, String>>();
	
	private static final ServiceLoader<DataObjectHandler> convertHandler = ServiceLoader.load(DataObjectHandler.class);
	
	public void prepareColumnToFieldMapFromCsvAndClass(String tableName, String[] columnNameList, Class<?> classForDO, Map<String, String> specialColumnMapper) throws Throwable {
		if (specialColumnMapper == null) {
			specialColumnMapper = new HashMap<String, String>();
		}
		String columnToFieldKey = getCacheKeyForColumnToFieldMap(tableName, classForDO);
		Map<String, String> columnToFieldMap = cacheForColumnToFieldMap.get(columnToFieldKey);
		if (columnToFieldMap == null) {
			Map<String, Class<?>> fieldClassMap = ClassUtil.getFieldClassMap(classForDO);
			columnToFieldMap = buildColumnToFieldMap(columnNameList, fieldClassMap, specialColumnMapper);
			cacheForColumnToFieldMap.put(columnToFieldKey, columnToFieldMap);
		}
	}
	
	public <T> T buildDataObjectFromCsv(Map<String, String> csvMap, T dataObj, String tableName) throws Throwable {
		Class<?> classForDO = dataObj.getClass();
		Map<String, String> columnToFieldMap = cacheForColumnToFieldMap.get(getCacheKeyForColumnToFieldMap(tableName, classForDO)); //有部分字段是取不到的 那是什么原因没取到呢？
		Map<String, Class<?>> fieldClassMap = ClassUtil.getFieldClassMap(classForDO);

		for (Map.Entry<String, String> entry : csvMap.entrySet()) {
			String columnName = entry.getKey().toLowerCase();
			String fieldName = columnToFieldMap.get(columnName);
			if (fieldName == null) {
				continue;
			}
			String valueFromCsv = entry.getValue().trim();
			if (valueFromCsv.isEmpty()) {
				continue;
			}
			
			if(fieldClassMap.get(fieldName)==null){
				continue;
			}
			
			Object objValueFromCsv = convertCsvValueToObject(valueFromCsv, fieldClassMap.get(fieldName));
			if (objValueFromCsv != null) {
				PropertyUtils.setProperty(dataObj, fieldName, objValueFromCsv);
			}
		}
		return dataObj;
	}
	
	public Map<String, Object> convertToAssertMapFromDO(Object dataObj) throws Throwable {
		Map<String, Object> dataFromDataObj = new HashMap<String, Object>();
		Class<?> classForDO = dataObj.getClass();
		Map<String, Class<?>> fieldClassMap = ClassUtil.getFieldClassMap(classForDO);
		for (String fieldName : fieldClassMap.keySet()) {
			dataFromDataObj.put(fieldName, PropertyUtils.getProperty(dataObj, fieldName));
		}
		return dataFromDataObj;
	}
	
	private String getCacheKeyForColumnToFieldMap(String tableName, Class<?> classForDO) {
		return tableName + classForDO.getName();
	}
	
	public Map<String, String> getColumnToFieldName(String tableName, Class<?> classForDO, boolean upperCase){
		String columnToFieldKey = getCacheKeyForColumnToFieldMap(tableName, classForDO);
		Map<String, String> map = cacheForColumnToFieldMap.get(columnToFieldKey);
		if(upperCase) {
			Map<String, String> uppermap = new ConcurrentHashMap<>();
			for (Map.Entry<String, String> entry : map.entrySet()) {
				uppermap.put(entry.getKey().toUpperCase(), entry.getValue());
			}
			map = uppermap;
		}
		return map;
	}
	
	private Map<String, String> buildColumnToFieldMap(String[] columnNameSet, Map<String, Class<?>> fieldClassMap, Map<String, String> specialFieldMapper) {
		Map<String, String> columnToFieldMap = new HashMap<String, String>();
		Map<String, String> fieldNameMap = new HashMap<String, String>();
		for (String fieldName : fieldClassMap.keySet()) {
			fieldNameMap.put(fieldName.toLowerCase(), fieldName);// 中间格式(没下杆，非驼峰)为key，驼峰fieldName为value
		}
		for (String columnNameOrigin : columnNameSet) {
			String columnName = columnNameOrigin.toLowerCase();
			String fieldNameLower = StringUtils.remove(columnName, '_').toLowerCase();// 变成没有下杆，都是小写的(非驼峰)的中间格式
			String fieldName = fieldNameMap.get(fieldNameLower);
			if (fieldName == null) {
				fieldName = specialFieldMapper.get(columnName);
			}
			if (fieldName == null) {
				continue;
			}
			columnToFieldMap.put(columnName, fieldName);
		}
		return columnToFieldMap;
	}
	
	private Object convertCsvValueToObject(String valueFromCsv, Class<?> classTypeFromDataObjField) throws Throwable {
		
		for (DataObjectHandler handler : convertHandler) {
			Object obj = handler.convert(valueFromCsv, classTypeFromDataObjField);
			if(obj != null) {
				return obj;
			}
		}

		Method method = null;
		try {
			method = classTypeFromDataObjField.getMethod("setId", Long.class);
		} catch (Exception e) {
			try {
				method = classTypeFromDataObjField.getMethod("setId", long.class);
			} catch (Exception e1) {
			}
		}

		if (method != null) {
			Long idForEntity = new Long(Long.parseLong(valueFromCsv));
			try {
				Object entity = classTypeFromDataObjField.newInstance();
				method.invoke(entity, idForEntity);
				return entity;
			} catch (Exception e) {
				e.printStackTrace();
				String msg = "{msg:'cant convert to DO', value:" + valueFromCsv + ", class:'" + classTypeFromDataObjField.getName() + "'}";
				throw new RuntimeException(msg, e);
			}
		}

		return null;
	}
}
